#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdarg.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <stddef.h>             /* offsetof */
#include <unistd.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/statfs.h>
#include <termios.h>
#include "fs.h"
#include "apptypedef.h"
#include "sysapi.h"
#include "sysarch.h"
#include "ComAPI.h"
#include "Rtc.h"
#include "board.h"

bool SetLinuxTime(const TTime& t);

static DWORD g_dwStartClick = 0;
static DWORD g_dwBaseClick = 0;  //�ڸ�ʱ���ʱ�����������ʱ��ǰ���Ѿ��ߵ�click
static OS_SEM g_semTime;

DWORD GetClick()
{
    return g_dwBaseClick + time(NULL) - g_dwStartClick;
}

DWORD GetTick()
{
    struct timeval tv;
    struct timezone tz;
    unsigned long msec;

    gettimeofday(&tv, &tz);

    msec = tv.tv_usec % 1000000 / 1000;

    return GetClick() * 1000 + msec;
}

//����:��DS3231��ȡ��ǰʱ��,�����õ�ϵͳʱ��
bool RTCInit()
{
    TTime time, tmOld;

    memset(&tmOld, 0, sizeof(tmOld));

    for (WORD i = 0; i < 10; i++)
    {
        memset(&time, 0, sizeof(time));
        RtcGetTime(time);
        Debug(DEBUG_CRITICAL, ("rtc: time%d %d-%02d-%02d %02d:%02d:%02d.\r\n",
                            i, time.nYear, time.nMonth, time.nDay,
                            time.nHour, time.nMinute, time.nSecond));

        if (!IsInvalidTime(time))
        {
            if (time.nYear == tmOld.nYear && time.nMonth == tmOld.nMonth &&
                time.nDay == tmOld.nDay && time.nHour == tmOld.nHour)
            {
                return SetLinuxTime(time);
            }

            tmOld = time;
        }
        else
        {
            memset(&tmOld, 0, sizeof(tmOld));
            Debug(DEBUG_CRITICAL, ("## rtc error!!!\r\n"));
        }

        Sleep(150);
    }

    if (ReadFile((char *)USER_PARA_PATH "savertc.clk", (BYTE* )&time, sizeof(time)))
    {
        if (!IsInvalidTime(time))
        {
            AddIntervs(time, TIME_UNIT_MINUTE, 2);
            tmOld = time;
            for (WORD i = 0; i < 10; i++)
            {
                time = tmOld;
                RtcSetTime(time);
                SetLinuxTime(time);
                Debug(DEBUG_CRITICAL, ("###rtc: recovery time from a file!!!\r\n"));

                memset(&time, 0, sizeof(time));
                RtcGetTime(time);
                Debug(DEBUG_CRITICAL, ("rtc: time%d %d-%02d-%02d %02d:%02d:%02d.\r\n",
                                    i, time.nYear, time.nMonth, time.nDay,
                                    time.nHour, time.nMinute, time.nSecond));

                if (!IsInvalidTime(time))
                {
                    if (time.nYear == tmOld.nYear && time.nMonth == tmOld.nMonth &&
                        time.nDay == tmOld.nDay && time.nHour == tmOld.nHour)
                    {
                        return true;
                    }
                }
                Sleep(150);
            }
        }
        else
        {
            time.nYear = 2000;
            time.nMonth = 1;
            time.nDay = 1;
            time.nHour = 0;
            time.nMinute = 0;
            time.nSecond = 0;
            time.nWeek = 1;
        }
    }

    return false;
}

void SyncTimer()
{
    static TTime tmLast = { 0 };
    TTime now;
    TTime tmOld;

    memset(&tmOld, 0, sizeof(tmOld));
    if (IsTimeEmpty(tmLast))
    {
        GetCurTime(&tmLast);
    }
    GetCurTime(&now);
    if (HoursPast(tmLast, now) > 0 && now.nMinute == 57 && now.nSecond >= 45) //ÿ��Сʱ��57��30��ͬ��һ��ʱ��
    {
        int err = 0;

        for (WORD i = 0; i < 3; i++)
        {
            memset(&now, 0, sizeof(now));
            RtcGetTime(now);
            Debug(DEBUG_CRITICAL, ("sync rtc: time%d %d-%02d-%02d %02d:%02d:%02d.\r\n",
                                i, now.nYear, now.nMonth, now.nDay,
                                now.nHour, now.nMinute, now.nSecond));

            if (!IsInvalidTime(now))
            {
                if (now.nYear == tmOld.nYear && now.nMonth == tmOld.nMonth &&
                    now.nDay == tmOld.nDay && now.nHour == tmOld.nHour)
                {
                    if (SetLinuxTime(now)) //ͬ��һ��ϵͳʱ��
                    {
                        GetCurTime(&tmLast);
                        return;
                    }
                }
                tmOld = now;
            }
            else
            {
                memset(&tmOld, 0, sizeof(tmOld));
                Debug(DEBUG_CRITICAL, ("sync rtc: ############ invalid\r\n"));
                //if (now.nYear>2050 || now.nMonth>12 || now.nMonth>12)
                {
                    err++;
                }
            }
            Sleep(1000);
        }

        GetCurTime(&tmLast);
        if (err > 2)
        {
            for (WORD i = 0; i < 10; i++)
            {
                RtcSetTime(tmLast);
                Debug(DEBUG_CRITICAL, ("###rtc: time to write back to RTC!!!\r\n"));

                memset(&now, 0, sizeof(now));
                RtcGetTime(now);
                Debug(DEBUG_CRITICAL, ("rtc: time%d %d-%02d-%02d %02d:%02d:%02d.\r\n",
                                    i, now.nYear, now.nMonth, now.nDay,
                                    now.nHour, now.nMinute, now.nSecond));

                if (!IsInvalidTime(now))
                {
                    if (now.nYear == tmLast.nYear && now.nMonth == tmLast.nMonth &&
                        now.nDay == tmLast.nDay && now.nHour == tmLast.nHour)
                    {
                        return;
                    }
                }
                Sleep(150);
            }
        }
    }
}

bool GetSysTime(TTime* pTime)
{
    struct tm *pCurTime;
    time_t curtime;

    OSSemPend(g_semTime);

    curtime = time(NULL); //lt1
    pCurTime = localtime(&curtime);
    pTime->nYear = pCurTime->tm_year + 1900;    //tm_year:��0 ��
    pTime->nMonth = pCurTime->tm_mon + 1;   //tm_mon:  0-11
    pTime->nDay = pCurTime->tm_mday;        //tm_mday: 1-31
    pTime->nHour = pCurTime->tm_hour;       //tm_hour: 0-23
    pTime->nMinute = pCurTime->tm_min;      //tm_min:  0-59
    pTime->nSecond = pCurTime->tm_sec;      //tm_sec:  0-61
    pTime->nWeek = pCurTime->tm_wday + 1;     //tm_wday: 0-6
    if (pTime->nYear < 2000)
    {
        pTime->nYear = 2000;
    }

    OSSemPost(g_semTime);

    return true;
}

bool SetSysTime(const TTime& t)
{
    if (IsInvalidTime(t))
    {
        Debug(DEBUG_CRITICAL, ("#####set system time:  invalid\r\n"));
        return false;
    }

    struct tm tmLinux;
    tmLinux.tm_sec = t.nSecond;  //int tm_sec;  ��ʾ���롹����[0,61]֮�䣬������������������������������õġ�
    tmLinux.tm_min = t.nMinute;  //int tm_min��ʾ���֡�����[0,59]֮�䡣
    tmLinux.tm_hour = t.nHour; //int tm_hour��ʾ��ʱ������[0,23]֮�䡣
    tmLinux.tm_mday = t.nDay;   //int tm_mday��ʾ�����µڼ��ա�����[1,31]֮�䡣
    tmLinux.tm_mon = t.nMonth - 1;  //int tm_mon��ʾ������ڼ��¡�����[0,11]֮�䡣
    tmLinux.tm_year = t.nYear - 1900; //int tm_yearҪ��1900��ʾ��һ�ꡣ��1900 ���������������

    OSSemPend(g_semTime);

    g_dwBaseClick += time(NULL) - g_dwStartClick; //�ڸ�ʱ���ʱ�����������ʱ��ǰ���Ѿ��ߵ�click

    time_t timet = timegm(&tmLinux);
    int iRet = stime(&timet); //����ϵͳ���ں�ʱ�䡣������t��ָ��ʱ��(������time��ص�ʱ��)д�������С�

    g_dwStartClick = time(NULL);  //���¼�����ʼ��clickʱ��

    OSSemPost(g_semTime);

    RtcSetTime(t);

    return iRet == 0;
}

bool SetLinuxTime(const TTime& t)
{
    struct tm tmLinux;

    tmLinux.tm_sec = t.nSecond;  //int tm_sec;  ��ʾ���롹����[0,61]֮�䣬������������������������������õġ�
    tmLinux.tm_min = t.nMinute;  //int tm_min��ʾ���֡�����[0,59]֮�䡣
    tmLinux.tm_hour = t.nHour; //int tm_hour��ʾ��ʱ������[0,23]֮�䡣
    tmLinux.tm_mday = t.nDay;   //int tm_mday��ʾ�����µڼ��ա�����[1,31]֮�䡣
    tmLinux.tm_mon = t.nMonth - 1;  //int tm_mon��ʾ������ڼ��¡�����[0,11]֮�䡣
    tmLinux.tm_year = t.nYear - 1900; //int tm_yearҪ��1900��ʾ��һ�ꡣ��1900 ���������������

    time_t timet = timegm(&tmLinux);
    int iRet = stime(&timet); //����ϵͳ���ں�ʱ�䡣������t��ָ��ʱ��(������time��ص�ʱ��)д�������С�

    return iRet == 0;
}

void SysInit()
{
    g_semTime = OSSemCreate(1);
    RTCInit();  //��DS3231��ʱ��ͬ����ϵͳʱ��
    g_dwBaseClick = 0;  //RTCInit()������SetSysTime(),�����g_dwBaseClick��ֵ��
                        //��������g_dwBaseClick����
    g_dwStartClick = time(NULL);
}

void SysCleanup()
{
}

bool g_fAppExit = false;

//����:��ǰӦ�ó����Ƿ������˳�
bool IsAppExit()
{
    return g_fAppExit;
}

//����:��ǰӦ�ó����Ƿ��˳����
bool IsAppExitDone()
{
    return true;
}

void ResetCPU()
{
	system("reboot\r\n");
	system("reboot\r\n");
}


//����:��λӦ�ó���
void ResetApp()
{
    Debug(DEBUG_CRITICAL, ("###*** Reset cpu...\r\n"));
    ClearWDG();
    g_fAppExit = true;
    system("sync");
    Sleep(2000);
    ResetCPU();
}


char *get_name(char *name, char *p)
{
    int namestart = 0, nameend = 0;

    while (isspace(p[namestart]))
    {
        namestart++;
    }
    nameend = namestart;
    while (p[nameend] && p[nameend] != ':' && !isspace(p[nameend]))
    {
        nameend++;
    }
    if (p[nameend] == ':')
    {
        if ((nameend - namestart) < 16)
        {
            memcpy(name, &p[namestart], nameend - namestart);
            name[nameend - namestart] = '\0';
            p = &p[nameend];
        }
        else
        {
            name[0] = '\0';
        }
    }
    else
    {
        name[0] = '\0';
    }
    return p + 1;
}

int IfReadListProc(char *target)
{
    /*static int proc_read;
       FILE *fh;
       char buf[512];
       struct interface *ife;
       int err, procnetdev_vsn;
       if (proc_read)return 0;
       if (!target)proc_read = 1;
       fh = fopen("/proc/net/dev", "r");
       if (!fh)
       {
        printf("Warning: cannot open /proc/net/dev. Limited output.\r\n");
        return -1;
       }
       fgets(buf, sizeof buf, fh);	// eat line
       fgets(buf, sizeof buf, fh);
       err = 0;
       while (fgets(buf, sizeof buf, fh))
       {
        char *s, name[128];
        s = get_name(name, buf);
        if (target && !strcmp(target, name))
        {
            err = 1;
            break;
        }
       }
       if (ferror(fh))
       {
        perror("/proc/net/dev");
        err = -1;
        proc_read = 0;
       }
       fclose(fh);
       return err;*/

    struct ifreq ifr;
    int fd;
    int err;
    unsigned long LocalIP, RemoteIP;

    strcpy(ifr.ifr_name, target);
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    err = ioctl(fd, SIOCGIFADDR, &ifr);
    if (err)
    {
        //perror("ioctl");
        close(fd);
        return 0;
    }
    memcpy(&LocalIP, ifr.ifr_addr.sa_data + 2, 4);
    //Debug(DEBUG_CRITICAL, ("#########Local  IP: %02d.%02d.%02d.%02d\r\n", (BYTE)(LocalIP&0x000000ff), (BYTE)((LocalIP>>8)&0x0000ff),
    //																  (BYTE)((LocalIP>>16)&0x00ff), (BYTE)((LocalIP>>24)&0xff)));

    err = ioctl(fd, SIOCGIFDSTADDR, &ifr);
    if (err)
    {
        //perror("ioctl");
        close(fd);
        return 0;
    }
    memcpy(&RemoteIP, ifr.ifr_addr.sa_data + 2, 4);
    close(fd);

    //Debug(DEBUG_CRITICAL, ("#########Remote IP: %02d.%02d.%02d.%02d\r\n", (BYTE)(RemoteIP&0x000000ff), (BYTE)((RemoteIP>>8)&0x0000ff),
    //																  (BYTE)((RemoteIP>>16)&0x00ff), (BYTE)((RemoteIP>>24)&0xff)));
    //if (LocalIP == RemoteIP)
    //	return -1;

    if (LocalIP != 0)
    {
        if ((RemoteIP & 0xff) == 192)
        {
            system("ifconfig eth0 193.168.13.8 up");
        }
        system("cp /etc/ppp/resolv.conf /etc/resolv.conf");
        return 1;
    }
    else
    {
        return 0;
    }
}

unsigned int freespace(char* disk)
{
    /*
       int i;
       struct statfs disk_statfs;
       printf("%d %d %d\r\n", sizeof(disk_statfs), sizeof(disk_statfs.f_blocks),
       sizeof(disk_statfs.f_ffree), sizeof(disk_statfs.f_fsid));
       printf("Get: %d\r\n", statfs("/opt/data", &disk_statfs));
       printf("f_type: %d\r\n", disk_statfs.f_type);
       printf("f_bsize: %d\r\n", disk_statfs.f_bsize);// ÿ��Ĵ�С(�ֽ���) bytes
       printf("f_blocks: %d\r\n", disk_statfs.f_blocks);
       printf("f_bfree: %d\r\n", disk_statfs.f_bfree);
       printf("f_bavail: %d\r\n", disk_statfs.f_bavail);// ���õĿ��� allbytes = f_bavail*f_bsize
       printf("f_files: %d\r\n", disk_statfs.f_files);
       printf("f_ffree: %d\r\n", disk_statfs.f_ffree);
     */
    struct statfs disk_statfs;

    statfs(disk, &disk_statfs);
    return disk_statfs.f_bavail * disk_statfs.f_bsize;
}

DWORD GetLocalAddr(char* interface)
{
    struct ifreq ifr;
    int fd;
    int err;
    unsigned long ip;

    strcpy(ifr.ifr_name, interface);
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    err = ioctl(fd, SIOCGIFADDR, &ifr);
    if (err)
    {
        //perror("ioctl");
        close(fd);
        return 0;
    }
    close(fd);
    memcpy(&ip, ifr.ifr_addr.sa_data + 2, 4);
    return ip;
}

//������ȷ��Ӧ����������Ҫ��Ŀ¼��������
bool InitDir()
{
    DIR* dir = opendir(USER_PATH "para");

    if (dir == NULL)
    {
        if (mkdir(USER_PATH "para", 0) == -1)
        {
            return false;
        }
    }
    else
    {
        closedir(dir);
    }

    dir = opendir(USER_PATH "data");
    if (dir == NULL)
    {
        if (mkdir(USER_PATH "data", 0) == -1)
        {
            return false;
        }
    }
    else
    {
        closedir(dir);
    }
    //140317 lik add begin 
	dir = opendir(USER_PATH"fact");
	if (dir == NULL)
	{
		if (mkdir(USER_PATH"fact", 0) == -1)
			return false;
	}
	else 
	{
		closedir(dir);
	}
    //140317 lik add end
    dir = opendir(USER_PATH "acpara");
    if (dir == NULL)
    {
        if (mkdir(USER_PATH "acpara", 0) == -1)
        {
            return false;
        }
    }
    else
    {
        closedir(dir);
    }

    dir = opendir(USER_PATH "metrcfg");
    if (dir == NULL)
    {
        if (mkdir(USER_PATH "metrcfg", 0) == -1)
        {
            return false;
        }
    }
    else
    {
        closedir(dir);
    }

	dir = opendir(USER_PATH "paracfg");
    if (dir == NULL)
    {
        if (mkdir(USER_PATH "paracfg", 0) == -1)
        {
            return false;
        }
    }
    else
    {
        closedir(dir);
    }

	dir = opendir(USER_PATH "upd");
    if (dir == NULL)
    {
        if (mkdir(USER_PATH "upd", 0) == -1)
        {
            return false;
        }
    }
    else
    {
        closedir(dir);
    }

    dir = opendir(USER_PATH "mp3");
    if (dir == NULL)
    {
        if (mkdir(USER_PATH "mp3", 0) == -1)
        {
            return false;
        }
    }
    else
    {
        closedir(dir);
    }
    
    return true;
}

static bool g_fConsoleClosed = false;

int CloseConsole(void)
{
    int ret;
    int fd;

    if (g_fConsoleClosed)
    {
        return 0;
    }
    fd = open("/dev/ttyS0", O_RDONLY); // �ı�console
    ret = ioctl(fd, TIOCCONS);
    close(fd);
    g_fConsoleClosed = true;

    return 1;
}

int OpenConsole(void)
{
    int ret;
    int fd;

    if (!g_fConsoleClosed)
    {
        return 0;
    }
    fd = open("/dev/console", O_RDONLY); // �ı�console
    ret = ioctl(fd, TIOCCONS);
    close(fd);
    system("stty -parenb cs8 speed 115200 rows 24");
    g_fConsoleClosed = false;
    return 1;
}

bool IsConsoleClosed()
{
    return g_fConsoleClosed;
}

void SetConsoleVal(bool var)
{
    g_fConsoleClosed = var;
}
